package cn.xinfei.xdecision.data.core.frame.listener;

import cn.xinfei.xdecision.common.model.datax.consts.VarPrometheusTagsConst;
import cn.xinfei.xdecision.common.model.datax.consts.VariableConst;
import cn.xinfei.xdecision.common.model.datax.enums.VariableStrategyType;
import cn.xinfei.xdecision.common.model.datax.exception.XDecisionDataException;
import cn.xinfei.xdecision.common.model.datax.exception.XDecisionDataExceptionType;
import cn.xinfei.xdecision.data.core.frame.strategy.StrategyContext;
import cn.xinfei.xdecision.data.core.frame.strategy.VariableStrategy;
import cn.xinfei.xdecision.data.core.frame.strategy.credit.CreditStrategy;
import cn.xinfei.xdecision.data.core.util.VariableConvertUtil;
import cn.xinfei.xdecision.data.core.vo.CreditNotifyResp;
import cn.xinfei.xdecision.data.core.vo.credit.CreditStatusDTO;
import cn.xinfei.xdecision.data.core.vo.credit.CreditStatusRequest;
import cn.xinfei.xdecision.model.CreditVarRequest;
import cn.xinfei.xdecision.model.CreditVarResponse;
import cn.xinfei.xdecision.model.VariableApiRequest;
import com.alibaba.fastjson.JSONObject;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

@Slf4j
@Component
public class CreditUploadRetryListener {

    @Autowired
    StrategyContext strategyContext;

    @Async
    @EventListener
    public void onCreditUploadRetryEvent(CreditUploadRetryEvent creditUploadRetryEvent) {
        long begin = System.currentTimeMillis();
        Transaction catT = Cat.newTransaction("credit-datasource", "credit-upload-retry");

        VariableApiRequest variableApiRequest = creditUploadRetryEvent.getData();
        log.info("requestId ={}，varCodes ={} 开始重新上报人行征信!",
                variableApiRequest.getRequestId(),
                JSONObject.toJSONString(variableApiRequest.getVarCodes()));
        CreditStrategy creditStrategy = (CreditStrategy) strategyContext.getStrategy(VariableStrategyType.CREDIT.name());
        CreditVarRequest creditVarRequest = VariableConvertUtil.toCreditVarRequest(variableApiRequest);

        creditStrategy.checkStrategyInput(creditVarRequest);
        creditStrategy.checkCreditChannel(creditVarRequest);

        String creditChannel = creditVarRequest.getInputParams().getString(VariableConst.CREDIT_CHANNEL);
        String app = variableApiRequest.getInputParams().getString(VariableConst.APP);
        String innerApp = variableApiRequest.getInputParams().getString(VariableConst.INNER_APP);

        try {
            if (!creditVarRequest.requestStrategys().contains(VariableStrategyType.CREDIT)) {
                log.info("request = {} fliter credit request", JSONObject.toJSONString(creditVarRequest));
            } else {
                JSONObject inputParams = creditVarRequest.inputParams();
                Long applyId = Optional.of(inputParams).get().getLong(VariableConst.APPLY_ID);
                CreditNotifyResp creditNotifyResp;
                try {
                    creditNotifyResp = creditStrategy.doCreditNotify(applyId, inputParams, creditChannel);
                    log.info("request = {} creditNotifyResp:{}", JSONObject.toJSONString(creditVarRequest), JSONObject.toJSONString(creditNotifyResp));
                    catT.setStatus(Transaction.SUCCESS);
                    Metrics.counter(VarPrometheusTagsConst.CREDIT_RETRY_UPLOAD_SUCCESS_COUNT,
                            VarPrometheusTagsConst.MetricsFliedTags.CREDIT_CHANNEL, creditChannel,
                            VarPrometheusTagsConst.MetricsFliedTags.APP, app,
                            VarPrometheusTagsConst.MetricsFliedTags.INNER_APP, innerApp).increment();
                } catch (Exception e) {
                    Cat.logError(e);
                    catT.setStatus(e);
                    log.error("requestId = {} error in onCreditUploadRetryEvent", variableApiRequest.getRequestId(), e);
                    throw new XDecisionDataException(XDecisionDataExceptionType.CODE_REQUEST_MIDOFFICE_ERROR, e);
                }
            }
        } catch (Exception e) {
            Cat.logError(e);
            catT.setStatus(e);
            log.error("error on CreditUploadRetryEvent request = {}", JSONObject.toJSONString(creditVarRequest), e);
            Metrics.counter(VarPrometheusTagsConst.CREDIT_RETRY_UPLOAD_FAIL_COUNT,
                    VarPrometheusTagsConst.MetricsFliedTags.CREDIT_CHANNEL, creditChannel,
                    VarPrometheusTagsConst.MetricsFliedTags.APP, app,
                    VarPrometheusTagsConst.MetricsFliedTags.INNER_APP, innerApp).increment();
            throw new XDecisionDataException(XDecisionDataExceptionType.DATA_CREDIT_UPLOAD_RETRY_ERROR, e);
        } finally {
            long end = System.currentTimeMillis();
            catT.complete();
            Metrics.counter(VarPrometheusTagsConst.CREDIT_RETRY_UPLOAD_REQUEST_COUNT,
                    VarPrometheusTagsConst.MetricsFliedTags.CREDIT_CHANNEL, creditChannel,
                    VarPrometheusTagsConst.MetricsFliedTags.APP, app,
                    VarPrometheusTagsConst.MetricsFliedTags.INNER_APP, innerApp).increment();

            Set<Tag> tagList = new HashSet<>();
            tagList.add(Tag.of(VarPrometheusTagsConst.MetricsFliedTags.CREDIT_CHANNEL, creditChannel));
            tagList.add(Tag.of(VarPrometheusTagsConst.MetricsFliedTags.APP, app));
            tagList.add(Tag.of(VarPrometheusTagsConst.MetricsFliedTags.INNER_APP, innerApp));
            Metrics.gauge(VarPrometheusTagsConst.CREDIT_RETRY_UPLOAD_DURATION, tagList, end - begin);
        }
    }
}
